/**
 * Projekt do předmetu GJA - LATEX TABLE CREATOR
 *
 * Soubor: ImportExport.java
 *
 * Provadi import/export souboru
 *
 * @author Ondřej Kubal  <xkluba00@stud.fit.vutbr.cz>
 * @author Petr Šimon    <xsimon10@stud.fit.vutbr.cz>
 */
package ImportExport;


import org.jdesktop.application.Action;
import org.jdesktop.application.ResourceMap;
import org.jdesktop.application.SingleFrameApplication;
import org.jdesktop.application.FrameView;
import org.jdesktop.application.TaskMonitor;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
import border.*;
import table.*;
import table.CellAttribute;
import java.io.*;
import java.util.ArrayList;
import java.util.StringTokenizer;


public class ImportExport {


    /**
     * Exportuje tabulku do formatu LaTeX
     *
     * @param jTable1   JTable s daty
     * @param cellSpan  Rozmery tabulky
     * @param model     Atributy tabulky (barvy apod.)
     *
     * @return Retezec s exportovanou tabulkou ve formatu LaTeX
     */
    public static String exportLatex(JTable jTable1, CellSpan cellSpan, AttributiveCellTableModel model)
    {
         //pokud prave uzivatel edituje bunku, tak editaci ukoncim
         if (jTable1.isEditing())
            jTable1.getCellEditor().stopCellEditing();

         //vystupni retezec.
         String vystup = new String();
         boolean changedColor = false;

         vystup = "\\begin{tabular}{*{"+jTable1.getColumnCount()+"}{l}}\n";


         CellBorder cellBorder;
         LinesBorder lb;

         //informace o stylu písma a zarovnani
         CellFont cellFont = (CellFont) model.getCellAttribute();
         //objekt s informacemi o rozmerech bunek
         CellAttribute cellAttr = (CellAttribute) model.getCellAttribute();

         //vsechny sloupce
         for (int y = 0; y < jTable1.getRowCount(); y++) {

             vystup += "\\hhline{";
             //projdu radek, abych mohl udelat horni ohraniceni
             for (int x = 0; x < jTable1.getColumnCount(); x++) {
                 //nactu informace o pojenych bunkach
                 int col = cellSpan.getSpan(y,x)[cellSpan.COLUMN];
                 int row = cellSpan.getSpan(y,x)[cellSpan.ROW];

                 //zjistim ohraniceni dane bunky
                 cellBorder = (CellBorder)model.getCellAttribute();
                 lb = (LinesBorder)cellBorder.getBorder(y+(row < 0 ? row : 0),x+(col<0 ? col : 0));
                 int topInnerBorder = 0;
                 int topOuterBorder = 0;
                 if (lb != null) {
                     topInnerBorder = lb.getInnerThickness().top;
                     topOuterBorder = lb.getOuterThickness().top;
                 }



                 if (cellSpan.getSpan(y,x)[cellSpan.ROW]>=0)
                 {
                     if (topOuterBorder>0) vystup += "=";
                     else if (topInnerBorder>0) vystup += "-";
                     else vystup += "~";
                 }
                 else vystup += "~";
             }
             vystup += "}\n";

             for (int x = 0; x < jTable1.getColumnCount(); x++) {
                     //zjistim text v dane bunce
                     Object obj_tmp = jTable1.getValueAt(y, x);
                     if (obj_tmp == null) obj_tmp = "";
                     String str = obj_tmp.toString();

                     int col = cellSpan.getSpan(y,x)[cellSpan.COLUMN];
                     int row = cellSpan.getSpan(y,x)[cellSpan.ROW];

                     //zjistim ohraniceni dane bunky
                     cellBorder = (CellBorder)model.getCellAttribute();
                     lb = (LinesBorder)cellBorder.getBorder(y+(row < 0 ? row : 0),x+(col<0 ? col : 0));
                     int leftInnerBorder = 0;
                     int rightInnerBorder = 0;
                     int leftOuterBorder = 0;
                     int rightOuterBorder = 0;
                     if (lb != null) {
                         leftInnerBorder = lb.getInnerThickness().left;
                         rightInnerBorder = lb.getInnerThickness().right;
                         leftOuterBorder = lb.getOuterThickness().left;
                         rightOuterBorder = lb.getOuterThickness().right;
                     }


                     if (col >= 0 && x>0) vystup += " & ";

                     if (col>1 || col>=0)
                     {
                         //bunka (pripadne slouceni vice bunek na jednom radku
                         vystup += "\\multicolumn{";
                         int tmp = row < 0 ? y+row : y;
                         vystup += (cellSpan.getSpan(tmp,x)[cellSpan.COLUMN]);
                         vystup += "}";

                         //ohraniceni bunky vlevo
                         vystup += "{"+(leftInnerBorder>0 ? "|" : "")+(leftOuterBorder>0 ? "|" : "");

                         //zjistim zarovnani textu v bunkach
                         int align = cellFont.getFontAtt(y, x);
                         //zarovnani textu v bunce
                         if (y==0 && cellAttr.getWidthType(x)!=cellAttr.SIZE_NONE)
                         { //pokud resim prvni radek a byla nastavena sirka sloupce
                             // nastavim zarovnani textu v bunnce
                             if ((align & cellFont.FLAG_H_A1) > 0 && (align & cellFont.FLAG_H_A2)>0) vystup += ">{\\raggedleft}";
                             else if ((align & cellFont.FLAG_H_A1) > 0) vystup += ">{\\centering}";
                             else vystup += ">{\\raggedright}";

                             //nastavim sirku sloupce
                             vystup += "p{"+cellAttr.getWidth(x)+cellAttr.getTypeString(cellAttr.getWidthType(x))+"}";
                         }
                         else {
                             if ((align & cellFont.FLAG_H_A1) > 0 && (align & cellFont.FLAG_H_A2)>0) vystup += "r";
                             else if ((align & cellFont.FLAG_H_A1) > 0) vystup += "c";
                             else vystup += "l";
                         }
                         //ohraniceni bunky vpravo
                         vystup += (rightInnerBorder>0 ? "|" : "")+(rightOuterBorder>0 ? "|" : "")+"}";

                         //obsah bunky
                         vystup += "{";

                         //barva pozadi
                         Color color = ((ColoredCell)model.getCellAttribute()).getBackground(y, x);
                         if (color != null) {
                             //poznamenam si, ze u nektere bunky byla zmenena barva pozadi. Budu muset do hlavicky pridat balicek
                             changedColor = true;
                             float rgb[] = new float[3];
                             color.getColorComponents(rgb);
                             vystup += "\\cellcolor[rgb]{"+rgb[0]+","+rgb[1]+","+rgb[2]+"}";
                         }


                         //pokud je to levy horni roh sloucenych bunek a pocet sloucenych radku je > jak 1, pak musim zadat prikaz multirow
                         if (row>1 && col >=1)
                             vystup += "\\multirow{"+(cellSpan.getSpan(y,x)[cellSpan.ROW])+"}{*}{";

                         //zacatek tucneho pisma
                         if ((cellFont.getFontAtt(y,x) & cellFont.FLAG_B) == cellFont.FLAG_B)
                             vystup += "\\textbf{";

                         //zacatek kurzivy
                         if ((cellFont.getFontAtt(y,x) & cellFont.FLAG_I) == cellFont.FLAG_I)
                             vystup += "\\textit{";

                         //zacatek monospace pisma
                         if ((cellFont.getFontAtt(y,x) & cellFont.FLAG_T) == cellFont.FLAG_T)
                             vystup += "\\texttt{";


                         if (row >=1)
                             vystup += str;

                         //konec monospace pisma
                         if ((cellFont.getFontAtt(y,x) & cellFont.FLAG_T) == cellFont.FLAG_T)
                             vystup += "}";

                         //konec kurzivy
                         if ((cellFont.getFontAtt(y,x) & cellFont.FLAG_I) == cellFont.FLAG_I)
                             vystup += "}";

                         //konec tucneho pisma
                         if ((cellFont.getFontAtt(y,x) & cellFont.FLAG_B) == cellFont.FLAG_B)
                             vystup += "}";


                         if (row>1 && col >=1)
                             vystup += "}";

                         vystup += "}";
                     }
                     else if (cellSpan.isVisible(y,x))
                         vystup += str;

             }
             vystup += " \\\\";
             //vyska radku
             if (cellAttr.getHeightType(y) != cellAttr.SIZE_NONE)
                 vystup += "["+(cellAttr.getHeight(y)/2.0) + cellAttr.getTypeString(cellAttr.getHeightType(y)) + "]";

             vystup += "\n";
         }

         vystup += "\\hhline{";
         //projdu radek, abych mohl udelat spodni ohraniceni
         for (int x = 0; x < jTable1.getColumnCount(); x++) {
             int y = jTable1.getRowCount()-1;
             //nactu informace o pojenych bunkach
             int col = cellSpan.getSpan(y,x)[cellSpan.COLUMN];
             int row = cellSpan.getSpan(y,x)[cellSpan.ROW];

             //zjistim ohraniceni dane bunky
             int topInnerBorder = 0;
             int topOuterBorder = 0;
             cellBorder = (CellBorder)model.getCellAttribute();

             lb = (LinesBorder)cellBorder.getBorder(y+(row < 0 ? row : 0),x+(col<0 ? col : 0));
             if (lb != null) {
                 topInnerBorder = lb.getInnerThickness().bottom;
                 topOuterBorder = lb.getOuterThickness().bottom;
             }

             if (topOuterBorder>0) vystup += "=";
             else if (topInnerBorder>0) vystup += "-";
             else vystup += "~";
         }
         vystup += "}\n";


         vystup += "\\end{tabular}"+"\n";
         
         //obalim tabulku do dokumentu
         vystup = "\\documentclass[a4paper]{article}\n\\usepackage[left=0cm,text={21cm, 28cm},top=1cm, includefoot]{geometry}\n"
                 + "\\usepackage{multirow}\n"
                 + "\\usepackage{hhline}\n"
                 + "\\usepackage[utf8]{inputenc}\n"
                 + (changedColor == true ? "\\usepackage[table]{xcolor}\n" : "") //pokud jsme zmenili pozadi bunky, musim pridat tento balicek
                 + "\\begin{document}\n"
                 + "\n"
                 + vystup;


         //konec dokumentu
         vystup += "\\end{document}\n";


         return vystup;
    }

    /**
     * Exportuje tabulku do CSV souboru
     *
     * @param jTable1       JTable tabulka s daty, ktera se exportuje
     * @param cellSpan      Rozmery tabulky
     * @param separator     Oddelovac sloupcu v tabulce
     *
     * @return Vystupni retezec s tabulkou v CSV formatu
     */
    public static String exportCSV(JTable jTable1, CellSpan cellSpan,char separator)
    {
         //pokud prave uzivatel edituje bunku, tak editaci ukoncim
         if (jTable1.isEditing())
            jTable1.getCellEditor().stopCellEditing();

         //vystupni retezec.
         String vystup = new String();

         //vsechny sloupce
         for (int y = 0; y < jTable1.getRowCount(); y++) {
             for (int x = 0; x < jTable1.getColumnCount(); x++) {
                     //zjistim text v dane bunce
                     Object obj_tmp = jTable1.getValueAt(y, x);
                     if (obj_tmp == null) obj_tmp = "";
                     String str = obj_tmp.toString();
                     //nahradim vsechny vyskyty " za dvojznak ""
                     str = str.replaceAll("\"", "\"\"");

                     int col = cellSpan.getSpan(y,x)[cellSpan.COLUMN];

                     if (col>0)
                         if (str.length()>0)
                            vystup += "\""+str+"\"";


                     //pokud nejsme na manci radku, tak pridam oddelovac ,
                     if (x < jTable1.getColumnCount()-1)
                         vystup += separator;
     
             }

             vystup += "\n";
         }


         return vystup;
    }


    /**
     * Nacte CSV soubor a aktualizuje GUI
     *
     * @param fileName      cesta k souboru
     * @param jTable1       reference na GUI tabulku
     * @param jSpinner1     Spinner box, kterym se nastavuje pocet sloupcu
     * @param jSpinner2     Spinner box, kterym se nastavuje pocet radku
     * @param separator     Oddelovac sloupcu v souboru
     */
    public static void importCSV(String fileName, JTable jTable1, JSpinner jSpinner1, JSpinner jSpinner2, char separator)
    {
        //pokud prave uzivatel edituje bunku, tak editaci ukoncim
        if (jTable1.isEditing())
           jTable1.getCellEditor().stopCellEditing();
        //ArrayList row = new ArrayList();
        int row = 0;
        int col = 0;

        try {
            BufferedReader br = new BufferedReader( new FileReader(fileName));
            String line = "";

            int i,state = 0;
            while ((i = br.read()) != -1) {
                char ch = (char)i;
                switch (state) {
                    case 0:
                        if (ch == '"') //prepnu se do dalsiho stavu, abych zkontroloval, zda nehodou nebude nasledovat dalsi uvozovky.
                            state = 1;
                        else if (ch == separator || ch == '\n') { //osetrim oddelovac nebo konec radku
                            jTable1.setValueAt(line, row, col);
                            line = "";
                            if (ch=='\n') {
                                row++;
                                col=0;
                            }
                            else col++;

                            //pokud je pocet sloupcu maly, tak pridam dalsi sloupec
                            if (col+1 > (Integer)jSpinner1.getValue())
                                jSpinner1.setValue(col+1);
                            //pokud je pocet radku maly, tak pridam dalsi radek
                            if (row+1 > (Integer)jSpinner2.getValue())
                                jSpinner2.setValue(row+1);
                        }
                        else //jinak pouze ulozim nacteny znak do retezce
                            line += ch;
                        break;
                    case 1:
                        if (ch == '"') { //pokud jsem opet nacetl uvozvoky, znamena to, ze je chci zobrazit (neni to rodoco znak)
                            state = 0;
                            line += ch;
                        }
                        else { //pokud to nejsou uvozovky, pak to znamena, ze je to zacatek rerezce
                            state = 2;
                            line += ch;
                        }
                        break;
                    case 2:
                        if (ch == '"') { //pokud jsem nacetl uvozovky, musim overit, zda dalsi znak taky neni uvozovky
                            state = 3;
                        }
                        else
                            line += ch;
                        break;
                    case 3:
                        if (ch == '"') { //opet jsem nacetl uvozovky, takze je pouze ulozim do retezce jako znak
                            state = 2;
                            line += ch;
                        }
                        else if (ch == separator || ch == '\n') { //osetrim oddelovac nebo konec radku
                            jTable1.setValueAt(line, row, col);
                            line = "";
                            if (ch=='\n') {
                                row++;
                                col=0;
                            }
                            else col++;

                            state = 0;

                            //pokud je pocet sloupcu maly, tak pridam dalsi sloupec
                            if (col+1 > (Integer)jSpinner1.getValue())
                                jSpinner1.setValue(col+1);
                            //pokud je pocet radku maly, tak pridam dalsi radek
                            if (row+1 > (Integer)jSpinner2.getValue())
                                jSpinner2.setValue(row+1);
                        }
                        else { //nacetl jsem neco jineho nez uvozovky, takze to znamena, ze jsem ukoncil retezec a musim aktualni zank opravdu prozkoumat
                            state = 0;
                            line += ch;
                        }
                        break;
                    default:
                        break;
                }
            }
            //pokud jsem na konci nacetl prazdny radek, tak ho odstranim
            if (col==0)
                jSpinner2.setValue(row);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}
